About
John P drew our attention to various species that were not shown as common in the NVC standards, but which we frequently find in our sites, notwithstanding they have been assessed as belonging to a community that “should” not have them at high frequency. Prominent among these is Stellaria graminea. The purpose of this notebook is to track the development of an application to find these unconforming species.
Start by loading the data
library(plotly)
source("db_extract.R")
the_data <- GetTheData()
And we’re going to need species_frequency by assembly; but maybe could decide to go by community?
frequency_by_assembly <- FrequencyByAssembly(the_data)
Error in .f(.x[[i]], ...) : object 'assembly_id' not found
Let’s plot mean frequency by assembly vs frequency by community for Stellaria graminea:
fba <- frequency_by_assembly %>% select(assembly_id, species_name, community, freq)
fbc <- frequency_by_community %>% select(species_name,community, freq)
jf <- left_join(fbc, fba, by = c("community", "species_name")) %>% filter(species_name == "Stellaria_graminea" & grepl("MG", community))
f <- ggplot(jf, aes(freq.x, freq.y, colour = community)) +
geom_point()+
xlab("frequency by community") + ylab("frequency by assembly")+
geom_segment(aes(x = 0, xend = 1, y = 0, yend = 1, colour ="red"))
print(f)

This is for S. graminea and the MG communities. So (a) there are lots more assemblies than there are communities (of course) and (b) frequency by assembly tends to be larger than frequency by community; aggregating over community has smoothed out a lot of variation. My feeling is that it will be more illuminating to eliminate the assembly variable to start with, we can explore variability with assembly later.
Next question: how to compare with standard values. Explore select into table mg_rodwell in the meadows database … in which we have columns community, species_id (and name, but not to be relied on) and p_central, the central frequency of the categories I .. V.
Stellaria graminea id 139. It so happens that p_central == 0.1 for S. graminea for all MG communities: SELECT Community, species_id, p_central FROM meadows.mg_rodwell where Community like “MG%” && species_id = 139; ( I wonder whether I can communicate directly with the DB from here using SQL?).
Anyway, it seems quite possible to collect the p_central values for all species and plot against frequency by community
q <- "SELECT Community, species_id, p_central FROM meadows.mg_rodwell where Community like 'MG%';"
std_freqs <- query(q)
Decimal MySQL column 2 imported as numeric
and match up with species frequencies by community
rm(jf) # We don't need it any more
jf1 <- left_join(frequency_by_community, std_freqs, by = c("community"="Community", "species_id"))
Lots of NAs here; (a) because mires (M) are included in the survey data but not in the mg_rodwell table - yet - because as its name implies, it is just the MG communities. And (b), because it seems we have detected some species that the standards don’t list in those communities at all. So (a), filter out all the mires; (b) set the remaining NAs to zero.
# Would be easier if we'd excluded mires from the_data to start with!
jf2 <- jf1 %>% filter(grepl("MG", community)) %>% replace_na(list(p_central = 0))
rm(jf1)
So now we want filter to include only cases where CrI5 > p_central or CrI95 < p_central, and then plot (survey) frequencies against standard frequencies (p_central)
jf3 <- jf2 %>% filter(CrI5 > p_central || CrI95 < p_central)
f2 <- ggplot(jf3, aes(p_central, freq, colour = community)) +
geom_jitter(aes(text = species_name), size = 3) + #, name = "species_name")+
xlab("Standard frequency") + ylab("Survey frequency")+
geom_segment(aes(x = 0, xend = 1, y = 0, yend = 1, colour ="red"))
Ignoring unknown aesthetics: text
ggplotly(f2)
# print(f2)
This gives a surprising number of species in strong disagrrement with the standard (we may ignore the big cluster near (0, 0) because of the way CrI5 is calculated - it can be very near zero, but not actually zero). Interactive plot: is this useful?
Even so, there’s too many species here for this to be a useful way of exploring the data. Filter out low frequency species, and then perhaps present the data as an interactive table.
Reduce species count.
There are 21375 records. Stellaria graminea accounts for 510 or 2.3859649%, so suggest reducing the data to species with less than 2% of the count. To start with, we have 288 species.
d1 <- (the_data
%>% select(records_id, species_id)
%>% group_by(species_id)
%>% summarise(cnt = n())
%>% mutate(frac = cnt/nrow(the_data))
%>% filter(frac >= 0.02))
Removing those accounting for less than 0.2% of the records leaves 13 species. Make the reduced dataset and plot survey frequency vs standard again, coded by species:
reduced <- left_join(d1, the_data, by = "species_id")
jf4 <- left_join(d1, jf3, by = "species_id")
f3 <- ggplot(jf4, aes(p_central, freq, colour = species_name)) +
geom_jitter(aes(text = species_name), size = 3) +
xlab("Standard frequency") + ylab("Survey frequency")+
geom_segment(aes(x = 0, xend = 1, y = 0, yend = 1, colour ="red"))
Ignoring unknown aesthetics: text
ggplotly(f3)
NA
This looks much more useful. Community is now available in the interactive part. Using 13 classes: on reflection (a) it might be better to use the top 12 classes (allowing to use ColorBrewer Paired Class 12 for the legend); and (b), ultimately to analyse by community (group, as used for poster BES2019) and select the top twelve species for each community.
Doing (b) first: sort out mg5a data:
cf <- head(the_data
%>% filter(community == "MG5a")
%>% group_by(species_id)
%>% summarise(hits = n()) %>% arrange(desc(hits)), 12)
d_mg5a <- the_data %>% filter(community == "MG5a") %>% right_join(cf, by = "species_id")
fc_mg5a <- FrequencyByCommunity(d_mg5a)
# Add standard frequencies
fc_mg5a <- (left_join(fc_mg5a, std_freqs, by = c("community"="Community", "species_id"))
%>% mutate(std_freq = replace_na(p_central, 0))
%>% select(-p_central))
f4 <- ggplot(fc_mg5a, aes(std_freq, freq, colour = species_name)) +
# geom_jitter(aes(text = species_name), size = 3) +
geom_pointrange(aes(ymin = CrI5, ymax = CrI95, text = species_name), size = 3) +
scale_colour_brewer(palette="Paired") +
xlab("Standard frequency") + ylab("Survey frequency") +
geom_segment(aes(x = 0, xend = 1, y = 0, yend = 1), colour ="red")
Ignoring unknown aesthetics: text
ggplotly(f4)
NA
The credibility intervals are tiny because we are working with 200 - 300 hits and over 400 trials. It will be interesting to see how this changes on an assembly basis, and in communities where we have less data.
Let’s try the same thing but on an assembly basis:
fa_mg5a <- FrequencyByAssembly(d_mg5a)
# Add standard frequencies
fa_mg5a <- (left_join(fa_mg5a, std_freqs, by = c("community"="Community", "species_name"))
%>% mutate(std_freq = replace_na(p_central, 0))
%>% select(-p_central))
Error: `by` can't contain join column `species_name` which is missing from RHS
Summarise with a searchable table.
LS0tDQp0aXRsZTogIlN0ZWxsYXJpYSBub3RlYm9vayINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojIEFib3V0DQoNCkpvaG4gUCBkcmV3IG91ciBhdHRlbnRpb24gdG8gdmFyaW91cyBzcGVjaWVzIHRoYXQgd2VyZSBub3Qgc2hvd24gYXMgY29tbW9uIGluIHRoZSBOVkMgc3RhbmRhcmRzLCBidXQgd2hpY2ggd2UgZnJlcXVlbnRseSBmaW5kIGluIG91ciBzaXRlcywgbm90d2l0aHN0YW5kaW5nIHRoZXkgaGF2ZSBiZWVuIGFzc2Vzc2VkIGFzIGJlbG9uZ2luZyB0byBhIGNvbW11bml0eSB0aGF0ICJzaG91bGQiIG5vdCBoYXZlIHRoZW0gYXQgaGlnaCBmcmVxdWVuY3kuIFByb21pbmVudCBhbW9uZyB0aGVzZSBpcyAqU3RlbGxhcmlhIGdyYW1pbmVhKi4gVGhlIHB1cnBvc2Ugb2YgdGhpcyBub3RlYm9vayBpcyB0byB0cmFjayB0aGUgZGV2ZWxvcG1lbnQgb2YgYW4gYXBwbGljYXRpb24gdG8gZmluZCB0aGVzZSB1bmNvbmZvcm1pbmcgc3BlY2llcy4NCg0KU3RhcnQgYnkgbG9hZGluZyB0aGUgZGF0YQ0KDQpgYGB7cn0NCmxpYnJhcnkocGxvdGx5KQ0Kc291cmNlKCJkYl9leHRyYWN0LlIiKQ0KdGhlX2RhdGEgPC0gR2V0VGhlRGF0YSgpDQpgYGANCg0KQW5kIHdlJ3JlIGdvaW5nIHRvIG5lZWQgc3BlY2llc19mcmVxdWVuY3kgYnkgYXNzZW1ibHk7IGJ1dCBtYXliZSBjb3VsZCBkZWNpZGUgdG8gZ28gYnkgY29tbXVuaXR5Pw0KYGBge3J9DQpmcmVxdWVuY3lfYnlfYXNzZW1ibHkgPC0gRnJlcXVlbmN5QnlBc3NlbWJseSh0aGVfZGF0YSkNCmZyZXF1ZW5jeV9ieV9jb21tdW5pdHkgPC0gRnJlcXVlbmN5QnlDb21tdW5pdHkodGhlX2RhdGEpDQpgYGANCkxldCdzIHBsb3QgbWVhbiBmcmVxdWVuY3kgYnkgYXNzZW1ibHkgdnMgZnJlcXVlbmN5IGJ5IGNvbW11bml0eSBmb3IgKlN0ZWxsYXJpYSBncmFtaW5lYSo6DQpgYGB7cn0NCmZiYSA8LSBmcmVxdWVuY3lfYnlfYXNzZW1ibHkgJT4lIHNlbGVjdChhc3NlbWJseV9pZCwgc3BlY2llc19uYW1lLCBjb21tdW5pdHksIGZyZXEpDQpmYmMgPC0gZnJlcXVlbmN5X2J5X2NvbW11bml0eSAlPiUgc2VsZWN0KHNwZWNpZXNfbmFtZSxjb21tdW5pdHksIGZyZXEpDQpqZiA8LSBsZWZ0X2pvaW4oZmJjLCBmYmEsIGJ5ID0gYygiY29tbXVuaXR5IiwgInNwZWNpZXNfbmFtZSIpKSAlPiUgZmlsdGVyKHNwZWNpZXNfbmFtZSA9PSAiU3RlbGxhcmlhX2dyYW1pbmVhIiAmIGdyZXBsKCJNRyIsIGNvbW11bml0eSkpDQpmIDwtIGdncGxvdChqZiwgYWVzKGZyZXEueCwgZnJlcS55LCBjb2xvdXIgPSBjb21tdW5pdHkpKSArDQogIGdlb21fcG9pbnQoKSsNCiAgeGxhYigiZnJlcXVlbmN5IGJ5IGNvbW11bml0eSIpICsgeWxhYigiZnJlcXVlbmN5IGJ5IGFzc2VtYmx5IikrDQogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHhlbmQgPSAxLCB5ID0gMCwgeWVuZCA9IDEsIGNvbG91ciA9InJlZCIpKQ0KcHJpbnQoZikNCmBgYA0KDQoNCmBgYHtyfQ0KYGBgDQpUaGlzIGlzIGZvciAqUy4gZ3JhbWluZWEqIGFuZCB0aGUgTUcgY29tbXVuaXRpZXMuIFNvIChhKSB0aGVyZSBhcmUgbG90cyBtb3JlIGFzc2VtYmxpZXMgdGhhbiB0aGVyZSBhcmUgY29tbXVuaXRpZXMgKG9mIGNvdXJzZSkgYW5kIChiKSBmcmVxdWVuY3kgYnkgYXNzZW1ibHkgdGVuZHMgdG8gYmUgbGFyZ2VyIHRoYW4gZnJlcXVlbmN5IGJ5IGNvbW11bml0eTsgYWdncmVnYXRpbmcgb3ZlciBjb21tdW5pdHkgaGFzIHNtb290aGVkIG91dCBhIGxvdCBvZiB2YXJpYXRpb24uIE15IGZlZWxpbmcgaXMgdGhhdCBpdCB3aWxsIGJlIG1vcmUgaWxsdW1pbmF0aW5nIHRvIGVsaW1pbmF0ZSB0aGUgYXNzZW1ibHkgdmFyaWFibGUgdG8gc3RhcnQgd2l0aCwgd2UgY2FuIGV4cGxvcmUgdmFyaWFiaWxpdHkgd2l0aCBhc3NlbWJseSBsYXRlci4NCg0KTmV4dCBxdWVzdGlvbjogaG93IHRvIGNvbXBhcmUgd2l0aCBzdGFuZGFyZCB2YWx1ZXMuIEV4cGxvcmUgc2VsZWN0IGludG8gdGFibGUgbWdfcm9kd2VsbCBpbiB0aGUgbWVhZG93cyBkYXRhYmFzZSAuLi4gaW4gd2hpY2ggd2UgaGF2ZSBjb2x1bW5zIGNvbW11bml0eSwgc3BlY2llc19pZCAoYW5kIG5hbWUsIGJ1dCBub3QgdG8gYmUgcmVsaWVkIG9uKSBhbmQgcF9jZW50cmFsLCB0aGUgY2VudHJhbCBmcmVxdWVuY3kgb2YgdGhlIGNhdGVnb3JpZXMgSSAuLiBWLg0KDQoqU3RlbGxhcmlhIGdyYW1pbmVhKiBpZCAxMzkuIEl0IHNvIGhhcHBlbnMgdGhhdCBwX2NlbnRyYWwgPT0gMC4xIGZvciAqUy4gZ3JhbWluZWEqIGZvciBhbGwgTUcgY29tbXVuaXRpZXM6DQpTRUxFQ1QgQ29tbXVuaXR5LCBzcGVjaWVzX2lkLCBwX2NlbnRyYWwgRlJPTSBtZWFkb3dzLm1nX3JvZHdlbGwgd2hlcmUgQ29tbXVuaXR5IGxpa2UgIk1HJSIgJiYgc3BlY2llc19pZCA9IDEzOTsNCiggSSB3b25kZXIgd2hldGhlciBJIGNhbiBjb21tdW5pY2F0ZSBkaXJlY3RseSB3aXRoIHRoZSBEQiBmcm9tIGhlcmUgdXNpbmcgU1FMPykuDQoNCkFueXdheSwgaXQgc2VlbXMgcXVpdGUgcG9zc2libGUgdG8gY29sbGVjdCB0aGUgcF9jZW50cmFsIHZhbHVlcyBmb3IgYWxsIHNwZWNpZXMgYW5kIHBsb3QgYWdhaW5zdCBmcmVxdWVuY3kgYnkgY29tbXVuaXR5DQoNCmBgYHtyfQ0KcSA8LSAiU0VMRUNUIENvbW11bml0eSwgc3BlY2llc19pZCwgcF9jZW50cmFsIEZST00gbWVhZG93cy5tZ19yb2R3ZWxsIHdoZXJlIENvbW11bml0eSBsaWtlICdNRyUnOyINCnN0ZF9mcmVxcyA8LSBxdWVyeShxKQ0KYGBgDQphbmQgbWF0Y2ggdXAgd2l0aCBzcGVjaWVzIGZyZXF1ZW5jaWVzIGJ5IGNvbW11bml0eQ0KYGBge3J9DQpybShqZikgIyBXZSBkb24ndCBuZWVkIGl0IGFueSBtb3JlDQpqZjEgPC0gbGVmdF9qb2luKGZyZXF1ZW5jeV9ieV9jb21tdW5pdHksIHN0ZF9mcmVxcywgYnkgPSBjKCJjb21tdW5pdHkiPSJDb21tdW5pdHkiLCAic3BlY2llc19pZCIpKQ0KDQpgYGANCg0KTG90cyBvZiBOQXMgaGVyZTsgKGEpIGJlY2F1c2UgbWlyZXMgKE0pIGFyZSBpbmNsdWRlZCBpbiB0aGUgc3VydmV5IGRhdGEgYnV0IG5vdCBpbiB0aGUgbWdfcm9kd2VsbCB0YWJsZSAtIHlldCAtIGJlY2F1c2UgYXMgaXRzIG5hbWUgaW1wbGllcywgaXQgaXMganVzdCB0aGUgTUcgY29tbXVuaXRpZXMuIEFuZCAoYiksIGJlY2F1c2UgaXQgc2VlbXMgd2UgaGF2ZSBkZXRlY3RlZCBzb21lIHNwZWNpZXMgdGhhdCB0aGUgc3RhbmRhcmRzIGRvbid0IGxpc3QgaW4gdGhvc2UgY29tbXVuaXRpZXMgYXQgYWxsLiBTbyAoYSksIGZpbHRlciBvdXQgYWxsIHRoZSBtaXJlczsgKGIpIHNldCB0aGUgcmVtYWluaW5nIE5BcyB0byB6ZXJvLg0KYGBge3J9DQojIFdvdWxkIGJlIGVhc2llciBpZiB3ZSdkIGV4Y2x1ZGVkIG1pcmVzIGZyb20gdGhlX2RhdGEgdG8gc3RhcnQgd2l0aCEgDQpqZjIgPC0gamYxICU+JSBmaWx0ZXIoZ3JlcGwoIk1HIiwgY29tbXVuaXR5KSkgJT4lIHJlcGxhY2VfbmEobGlzdChwX2NlbnRyYWwgPSAwKSkNCnJtKGpmMSkNCmBgYA0KU28gbm93IHdlIHdhbnQgZmlsdGVyIHRvIGluY2x1ZGUgb25seSBjYXNlcyB3aGVyZSBDckk1ID4gcF9jZW50cmFsIG9yIENySTk1IDwgcF9jZW50cmFsLCBhbmQgdGhlbiBwbG90IChzdXJ2ZXkpIGZyZXF1ZW5jaWVzIGFnYWluc3Qgc3RhbmRhcmQgZnJlcXVlbmNpZXMgKHBfY2VudHJhbCkNCmBgYHtyfQ0KamYzIDwtIGpmMiAlPiUgZmlsdGVyKENySTUgPiBwX2NlbnRyYWwgfHwgQ3JJOTUgPCBwX2NlbnRyYWwpDQpmMiA8LSBnZ3Bsb3QoamYzLCBhZXMocF9jZW50cmFsLCBmcmVxLCBjb2xvdXIgPSBjb21tdW5pdHkpKSArDQogIGdlb21faml0dGVyKGFlcyh0ZXh0ID0gc3BlY2llc19uYW1lKSwgc2l6ZSA9IDMpICsgIywgbmFtZSA9ICJzcGVjaWVzX25hbWUiKSsNCiAgeGxhYigiU3RhbmRhcmQgZnJlcXVlbmN5IikgKyB5bGFiKCJTdXJ2ZXkgZnJlcXVlbmN5IikrDQogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHhlbmQgPSAxLCB5ID0gMCwgeWVuZCA9IDEsIGNvbG91ciA9InJlZCIpKQ0KZ2dwbG90bHkoZjIpDQojIHByaW50KGYyKQ0KDQpgYGANClRoaXMgZ2l2ZXMgYSBzdXJwcmlzaW5nIG51bWJlciBvZiBzcGVjaWVzIGluIHN0cm9uZyBkaXNhZ3JyZW1lbnQgd2l0aCB0aGUgc3RhbmRhcmQgKHdlIG1heSBpZ25vcmUgdGhlIGJpZyBjbHVzdGVyIG5lYXIgKDAsIDApIGJlY2F1c2Ugb2YgdGhlIHdheSBDckk1IGlzIGNhbGN1bGF0ZWQgLSBpdCBjYW4gYmUgdmVyeSBuZWFyIHplcm8sIGJ1dCBub3QgYWN0dWFsbHkgemVybykuIEludGVyYWN0aXZlIHBsb3Q6IGlzIHRoaXMgdXNlZnVsPw0KDQpFdmVuIHNvLCB0aGVyZSdzIHRvbyBtYW55IHNwZWNpZXMgaGVyZSBmb3IgdGhpcyB0byBiZSBhIHVzZWZ1bCB3YXkgb2YgZXhwbG9yaW5nIHRoZSBkYXRhLiBGaWx0ZXIgb3V0IGxvdyBmcmVxdWVuY3kgc3BlY2llcywgYW5kIHRoZW4gcGVyaGFwcyBwcmVzZW50IHRoZSBkYXRhIGFzIGFuIGludGVyYWN0aXZlIHRhYmxlLg0KDQojIyMgUmVkdWNlIHNwZWNpZXMgY291bnQuDQpUaGVyZSBhcmUgYHIgbnJvdyh0aGVfZGF0YSlgIHJlY29yZHMuICpTdGVsbGFyaWEgZ3JhbWluZWEqIGFjY291bnRzIGZvciBgciB0aGVfZGF0YSAlPiUgc2VsZWN0KHNwZWNpZXNfaWQsIHJlY29yZHNfaWQpICU+JSBmaWx0ZXIoc3BlY2llc19pZCA9PSAxMzkpICU+JSBucm93KClgDQpvciBgciAxMDAqKHRoZV9kYXRhICU+JSBzZWxlY3Qoc3BlY2llc19pZCwgcmVjb3Jkc19pZCkgJT4lIGZpbHRlcihzcGVjaWVzX2lkID09IDEzOSkgJT4lIG5yb3coKSkvbnJvdyh0aGVfZGF0YSlgJSwgc28gc3VnZ2VzdCByZWR1Y2luZyB0aGUgZGF0YSB0byBzcGVjaWVzIHdpdGggbGVzcyB0aGFuIDIlIG9mIHRoZSBjb3VudC4gVG8gc3RhcnQgd2l0aCwgd2UgaGF2ZSBgciB0aGVfZGF0YSAlPiUgc2VsZWN0KHNwZWNpZXNfaWQpICU+JSBkaXN0aW5jdCgpICU+JSBucm93KClgIHNwZWNpZXMuIA0KYGBge3J9DQpkMSA8LSAodGhlX2RhdGEgDQogICAgICAgJT4lIHNlbGVjdChyZWNvcmRzX2lkLCBzcGVjaWVzX2lkKSANCiAgICAgICAlPiUgZ3JvdXBfYnkoc3BlY2llc19pZCkgDQogICAgICAgJT4lIHN1bW1hcmlzZShjbnQgPSBuKCkpDQogICAgICAgJT4lIG11dGF0ZShmcmFjID0gY250L25yb3codGhlX2RhdGEpKQ0KICAgICAgICU+JSBmaWx0ZXIoZnJhYyA+PSAwLjAyKSkNCmBgYA0KUmVtb3ZpbmcgdGhvc2UgYWNjb3VudGluZyBmb3IgbGVzcyB0aGFuIDAuMiUgb2YgdGhlIHJlY29yZHMgbGVhdmVzIGByIG5yb3coZDEpYCBzcGVjaWVzLg0KTWFrZSB0aGUgcmVkdWNlZCBkYXRhc2V0IGFuZCBwbG90IHN1cnZleSBmcmVxdWVuY3kgdnMgc3RhbmRhcmQgYWdhaW4sIGNvZGVkIGJ5IHNwZWNpZXM6DQpgYGB7cn0NCnJlZHVjZWQgPC0gbGVmdF9qb2luKGQxLCB0aGVfZGF0YSwgYnkgPSAic3BlY2llc19pZCIpDQpqZjQgPC0gbGVmdF9qb2luKGQxLCBqZjMsIGJ5ID0gInNwZWNpZXNfaWQiKQ0KZjMgPC0gZ2dwbG90KGpmNCwgYWVzKHBfY2VudHJhbCwgZnJlcSwgY29sb3VyID0gc3BlY2llc19uYW1lKSkgKw0KICBnZW9tX2ppdHRlcihhZXModGV4dCA9IHNwZWNpZXNfbmFtZSksIHNpemUgPSAzKSArIA0KICB4bGFiKCJTdGFuZGFyZCBmcmVxdWVuY3kiKSArIHlsYWIoIlN1cnZleSBmcmVxdWVuY3kiKSsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMCwgeGVuZCA9IDEsIHkgPSAwLCB5ZW5kID0gMSwgY29sb3VyID0icmVkIikpDQpnZ3Bsb3RseShmMykNCg0KYGBgDQpUaGlzIGxvb2tzIG11Y2ggbW9yZSB1c2VmdWwuIENvbW11bml0eSBpcyBub3cgYXZhaWxhYmxlIGluIHRoZSBpbnRlcmFjdGl2ZSBwYXJ0LiBVc2luZyAxMyBjbGFzc2VzOiBvbiByZWZsZWN0aW9uIChhKSBpdCBtaWdodCBiZSBiZXR0ZXIgdG8gdXNlIHRoZSB0b3AgMTIgY2xhc3NlcyAoYWxsb3dpbmcgdG8gdXNlIENvbG9yQnJld2VyIFBhaXJlZCBDbGFzcyAxMiBmb3IgdGhlIGxlZ2VuZCk7IGFuZCAoYiksIHVsdGltYXRlbHkgdG8gYW5hbHlzZSBieSBjb21tdW5pdHkgKGdyb3VwLCBhcyB1c2VkIGZvciBwb3N0ZXIgQkVTMjAxOSkgYW5kIHNlbGVjdCB0aGUgdG9wIHR3ZWx2ZSBzcGVjaWVzIGZvciBlYWNoIGNvbW11bml0eS4NCg0KRG9pbmcgKGIpIGZpcnN0OiBzb3J0IG91dCBtZzVhIGRhdGE6DQpgYGB7cn0NCg0KY2YgPC0gaGVhZCh0aGVfZGF0YSANCiAgICAgICAgICAgJT4lIGZpbHRlcihjb21tdW5pdHkgPT0gIk1HNWEiKQ0KICAgICAgICAgICAlPiUgZ3JvdXBfYnkoc3BlY2llc19pZCkgDQogICAgICAgICAgICU+JSBzdW1tYXJpc2UoaGl0cyA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhoaXRzKSksIDEyKQ0KZF9tZzVhIDwtIHRoZV9kYXRhICU+JSBmaWx0ZXIoY29tbXVuaXR5ID09ICJNRzVhIikgJT4lIHJpZ2h0X2pvaW4oY2YsIGJ5ID0gInNwZWNpZXNfaWQiKQ0KZmNfbWc1YSA8LSBGcmVxdWVuY3lCeUNvbW11bml0eShkX21nNWEpDQojIEFkZCBzdGFuZGFyZCBmcmVxdWVuY2llcw0KZmNfbWc1YSA8LSAobGVmdF9qb2luKGZjX21nNWEsIHN0ZF9mcmVxcywgYnkgPSBjKCJjb21tdW5pdHkiPSJDb21tdW5pdHkiLCAic3BlY2llc19pZCIpKSANCiAgICAgICAgICAgICU+JSBtdXRhdGUoc3RkX2ZyZXEgPSByZXBsYWNlX25hKHBfY2VudHJhbCwgMCkpIA0KICAgICAgICAgICAgJT4lIHNlbGVjdCgtcF9jZW50cmFsKSkNCg0KZjQgPC0gZ2dwbG90KGZjX21nNWEsIGFlcyhzdGRfZnJlcSwgZnJlcSwgY29sb3VyID0gc3BlY2llc19uYW1lKSkgKw0KICAjIGdlb21faml0dGVyKGFlcyh0ZXh0ID0gc3BlY2llc19uYW1lKSwgc2l6ZSA9IDMpICsgDQogIGdlb21fcG9pbnRyYW5nZShhZXMoeW1pbiA9IENySTUsIHltYXggPSBDckk5NSwgdGV4dCA9IHNwZWNpZXNfbmFtZSksIHNpemUgPSAzKSArIA0KICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGU9IlBhaXJlZCIpICsNCiAgeGxhYigiU3RhbmRhcmQgZnJlcXVlbmN5IikgKyB5bGFiKCJTdXJ2ZXkgZnJlcXVlbmN5IikgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB4ZW5kID0gMSwgeSA9IDAsIHllbmQgPSAxKSwgY29sb3VyID0icmVkIikNCmdncGxvdGx5KGY0KQ0KDQpgYGANCg0KVGhlIGNyZWRpYmlsaXR5IGludGVydmFscyBhcmUgdGlueSBiZWNhdXNlIHdlIGFyZSB3b3JraW5nIHdpdGggMjAwIC0gMzAwIGhpdHMgYW5kIG92ZXIgNDAwIHRyaWFscy4gSXQgd2lsbCBiZSBpbnRlcmVzdGluZyB0byBzZWUgaG93IHRoaXMgY2hhbmdlcyBvbiBhbiBhc3NlbWJseSBiYXNpcywgYW5kIGluIGNvbW11bml0aWVzIHdoZXJlIHdlIGhhdmUgbGVzcyBkYXRhLg0KDQpMZXQncyB0cnkgdGhlIHNhbWUgdGhpbmcgYnV0IG9uIGFuIGFzc2VtYmx5IGJhc2lzOg0KYGBge3J9DQpmYV9tZzVhIDwtIEZyZXF1ZW5jeUJ5QXNzZW1ibHkoZF9tZzVhKQ0KIyBBZGQgc3RhbmRhcmQgZnJlcXVlbmNpZXMNCmZhX21nNWEgPC0gKGxlZnRfam9pbihmYV9tZzVhLCBzdGRfZnJlcXMsIGJ5ID0gYygiY29tbXVuaXR5Ij0iQ29tbXVuaXR5IiwgInNwZWNpZXNfaWQiKSkgDQogICAgICAgICAgICAlPiUgbXV0YXRlKHN0ZF9mcmVxID0gcmVwbGFjZV9uYShwX2NlbnRyYWwsIDApKSANCiAgICAgICAgICAgICU+JSBzZWxlY3QoLXBfY2VudHJhbCkpDQoNCmBgYA0KDQpTdW1tYXJpc2Ugd2l0aCBhIHNlYXJjaGFibGUgdGFibGUuDQoNCg0KDQoNCg0K